using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using MIMPGameLibrary;

namespace MIMP
{

    /// <summary>
    /// This DrawableGameComponent represents the "control panel"--the lower 1/4 of the screen which contains
    /// most of the UI elements of the game. Its job is to: 1) Draw the control panel, and 2) Fire input events
    /// when a control panel button (like Move, Attack, End Turn, etc) is clicked.
    /// </summary>
    public partial class GameplayScreen : GameScreen, IGameplayScreenService
    {
        Texture2D panelSprite;
        Texture2D buttonOutline;

        List<UIButtonDisplay> SetupPhaseButtons;
        List<UIButtonDisplay> PlayPhaseButtons;

        void ControlPanelConstructor()
        {
            SetupPhaseButtons = new List<UIButtonDisplay>();
            PlayPhaseButtons = new List<UIButtonDisplay>();
        }

        void LoadControlPanelContent()
        {
            try
            {
                panelSprite = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "control-panel");
                buttonOutline = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "button-outline");

                Texture2D prev = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "prev-button");
                SetupPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH / 4,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + 10), 1, prev, Keys.OemComma, UIButtons.Prev));

                Texture2D next = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "next-button");
                SetupPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH / 4,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + 20 + prev.Height), 1, next, Keys.OemPeriod, UIButtons.Next));

                Texture2D add = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "add-button");
                SetupPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH / 4 + 10 + prev.Width,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + 10), 1, add, Keys.Insert, UIButtons.Add));

                Texture2D del = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "delete-button");
                SetupPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH / 4 + 10 + next.Width,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + 20 + add.Height), 1, del, Keys.Delete, UIButtons.Del));

                Texture2D ok = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "ok-button");
                SetupPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH - ok.Width - 10,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + 10), 1, ok, Keys.Enter, UIButtons.SetupDone));
                PlayPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH - ok.Width * 3 - 30,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + 10), 1, ok, Keys.Enter, UIButtons.SelectDefenders, false, false));

                Texture2D attack = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "attack-button");
                PlayPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH - attack.Width - 10,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + 10), 1, attack, Keys.A, UIButtons.Attack));

                Texture2D end = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "end-button");
                PlayPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH - end.Width - 10,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + end.Height + 20), 1, end, Keys.End, UIButtons.EndTurn));

                Texture2D menu = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "menu-button");
                PlayPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH - menu.Width - 10,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + menu.Height * 2 + 30), 1, menu, Keys.Escape, UIButtons.Menu));
                SetupPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH - menu.Width - 10,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + menu.Height * 2 + 30), 1, menu, Keys.Escape, UIButtons.Menu));

                Texture2D help = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "help-button");
                PlayPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH - help.Width * 2 - 20,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + help.Height * 2 + 30), 1, help, Keys.H, UIButtons.Help));
                SetupPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH - help.Width * 2 - 20,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + help.Height * 2 + 30), 1, help, Keys.H, UIButtons.Help));

                Texture2D move = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "move-button");
                PlayPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH - move.Width - move.Width - 20,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + 10), 1, move, Keys.M, UIButtons.Move));

                Texture2D secondmove = game.Content.Load<Texture2D>(MIMPGame.CONROL_PANEL_SPRITES_DIR + "second-move-button");
                PlayPhaseButtons.Add(new UIButtonDisplay(MIMPGame.WINDOW_WIDTH - secondmove.Width * 2 - 20,
                    (int)(MIMPGame.WIDOW_HEIGHT * 0.75 + secondmove.Height + 20), 1, secondmove, Keys.S, UIButtons.SecondMove));
            }
            catch (System.IO.FileNotFoundException fnfe)
            {
                ExceptionPolicy.HandleException(fnfe, "MIMP Exception Policy");
            }

            base.LoadContent();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        void HandleControlPanelInput(InputState input)
        {
            List<UIButtonDisplay> UIButtonDisplays = gsService.GameState.Phase == GameState.Phases.Setup ? SetupPhaseButtons : PlayPhaseButtons;
            
            foreach (UIButtonDisplay btn in UIButtonDisplays)
            {
                btn.SetIsMouseOver(input.CurrentMouseState);
                if (input.IsNewKeyRelease(btn.ShortcutKey) && btn.IsClickable)
                {
                    if (UIButtonLeftClicked != null)
                    {
                        ConsoleModifiers mods = GetModifiers(input.CurrentKeyboardStates[0]);
                        UIButtonLeftClicked(this, new UIButtonClickEventArgs(btn.ButtonID, mods));
                        return;
                    }
                }
            }
            //TODO: add check to see if mouse is somewhere over the control panel (do not bother doing all this stuff if it is not)
            if (input.IsNewLeftMouseClick())
            {
                UIButtonDisplay clicked = UIButtonDisplays.Find(delegate(UIButtonDisplay btn) { return btn.IsMouseOver; });
                if (clicked != null)
                {
                    if (UIButtonLeftClicked != null)
                    {
                        ConsoleModifiers mods = GetModifiers(input.CurrentKeyboardStates[0]);
                        UIButtonLeftClicked(this, new UIButtonClickEventArgs(clicked.ButtonID, mods));
                    }
                }
            }
            //...and do the same for right clicks
            else if (input.IsNewRightMouseClick())
            {
                UIButtonDisplay clicked = UIButtonDisplays.Find(delegate(UIButtonDisplay btn) { return btn.IsMouseOver; });
                if (clicked != null)
                {
                    if (UIButtonRightClicked != null)
                    {
                        ConsoleModifiers mods = GetModifiers(input.CurrentKeyboardStates[0]);
                        UIButtonRightClicked(this, new UIButtonClickEventArgs(clicked.ButtonID, mods));
                    }
                }
            }
        }

        ConsoleModifiers GetModifiers(KeyboardState cur)
        {
            ConsoleModifiers mods = 0;
            if (cur.IsKeyDown(Keys.LeftShift) || cur.IsKeyDown(Keys.RightShift))
            {
                mods |= ConsoleModifiers.Shift;
            }
            if (cur.IsKeyDown(Keys.LeftControl) || cur.IsKeyDown(Keys.RightControl))
            {
                mods |= ConsoleModifiers.Control;
            }
            if (cur.IsKeyDown(Keys.LeftAlt) || cur.IsKeyDown(Keys.RightAlt))
            {
                mods |= ConsoleModifiers.Alt;
            }
            return mods;
        }
        /// <summary>
        /// This is called when the control panel should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        void DrawControlPanel(GameTime gameTime)
        {
            List<UIButtonDisplay> UIButtonDisplays = gsService.GameState.Phase == GameState.Phases.Setup ? SetupPhaseButtons : PlayPhaseButtons;
            ScreenManager.SpriteBatch.Begin();
            ScreenManager.SpriteBatch.Draw(panelSprite, new Rectangle(0, (int)(MIMPGame.WIDOW_HEIGHT * .75),
                MIMPGame.WINDOW_WIDTH, (int)(MIMPGame.WINDOW_WIDTH * 0.25)), Color.White);
            foreach (UIButtonDisplay btn in UIButtonDisplays)
            {
                if (btn.IsVisible)
                {
                    ScreenManager.SpriteBatch.Draw(btn.Sprite, btn.Bounds, Color.White);
                    Color outlineColor = Color.White;
                    if (gsService.ActiveButton == btn.ButtonID && btn.ButtonID != UIButtons.SelectDefenders)
                    {
                        outlineColor = Color.Red;
                    }
                    ScreenManager.SpriteBatch.Draw(buttonOutline, btn.Bounds, outlineColor);
                }
            }

            Vector2 statusPos = new Vector2(MIMPGame.WINDOW_WIDTH / 2 - ScreenManager.Font.MeasureString(gsService.StatusMsg).X / 2,
                (float)(MIMPGame.WIDOW_HEIGHT - 25));
            ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, gsService.StatusMsg, statusPos, Color.Black);

            DrawButtonNameText();
            DrawActivePlayerText();
            DrawAddMonsterStats();
            DrawViewedMonsterStats();
            ScreenManager.SpriteBatch.End();
            //infoBox is defined in GameplayScreen.cs
            infoBox.Draw(gameTime, ScreenManager.SpriteBatch);
        }
        private void DrawViewedMonsterStats()
        {
            if (gameState.Phase == GameState.Phases.Setup) { return; }

            Vector2 textShadow = new Vector2(1, 1);
            Vector2 textCenter = new Vector2(20, MIMPGame.WIDOW_HEIGHT + 10 - MIMPGame.WIDOW_HEIGHT / 4);
            if (gsService.GameState.Phase == GameState.Phases.Setup)
            {
                textCenter = new Vector2(MIMPGame.WINDOW_WIDTH / 4, MIMPGame.WIDOW_HEIGHT + 10 - MIMPGame.WIDOW_HEIGHT / 4);
            }
            String text;
            Monster m = gsService.ViewingMonster;
            if (m != null)
            {
                text = m.GetMonsterInfoString(gameState.Phase);
            }
            else
            {
                text = "Select a monster with\nthe left mouse button.";
            }

            ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, text, textCenter, Color.Black);
        }
        private void DrawAddMonsterStats()
        {
            if (gsService.GameState.Phase == GameState.Phases.Play) { return; }
            Vector2 textCenter = new Vector2(10, MIMPGame.WIDOW_HEIGHT * 3 / 4 + 10);
            String text = "";
            Monster m = gsService.MonsterToAdd;
            if (m != null)
            {
                text = m.GetMonsterInfoString(gameState.Phase);
            }
            else
            {
                text = "No monsters to add!";
            }
            ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, text, textCenter, Color.Black);
        }

        private void DrawButtonNameText()
        {
            List<UIButtonDisplay> UIButtonDisplays = gsService.GameState.Phase == GameState.Phases.Setup ? SetupPhaseButtons : PlayPhaseButtons;
            UIButtonDisplay hovering = UIButtonDisplays.Find(delegate(UIButtonDisplay d) { return d.IsMouseOver; });
            if (hovering != null)
            {
                String buttonName = UIButtonDisplay.UIBUttonName(hovering.ButtonID);
                Vector2 buttonNamePos = new Vector2(MIMPGame.WINDOW_WIDTH - 10, MIMPGame.WIDOW_HEIGHT);
                buttonNamePos -= ScreenManager.Font.MeasureString(buttonName);
                ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, buttonName, buttonNamePos, Color.DimGray);
            }
        }

        private void DrawActivePlayerText()
        {
            String name = gameState.ActivePlayer.ToString();
            Vector2 pos = new Vector2(10, MIMPGame.WIDOW_HEIGHT - ScreenManager.Font.MeasureString(name).Y);
            ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, name, pos, gameState.ActivePlayer.Color);
            if (gameState.Phase == GameState.Phases.Setup)
            {
                String text = "" + gameState.ActivePlayer.DeploymentPoints + " deployment points left";
                pos = new Vector2(10, MIMPGame.WIDOW_HEIGHT - ScreenManager.Font.MeasureString(text).Y - ScreenManager.Font.MeasureString(name).Y);
                ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, text, pos, Color.DimGray);
            }
        }

        private void ChangeActiveButtonsHandler(object sender, EventArgs e)
        {
            ChangeActiveButtonsArgs args = (ChangeActiveButtonsArgs)e;
            List<UIButtonDisplay> UIButtonDisplays = gsService.GameState.Phase == GameState.Phases.Setup ? SetupPhaseButtons : PlayPhaseButtons;
            foreach (UIButtonDisplay btn in UIButtonDisplays)
            {
                if (args.ActiveButtons.Contains(btn.ButtonID))
                {
                    btn.IsVisible = true;
                    btn.IsClickable = true;
                }
                else
                {
                    btn.IsVisible = false;
                    btn.IsClickable = false;
                }
            }
        }
    }
}